#!/usr/bin/env python
import os
import sys
import unittest

# Expand system path with tested library source.
libnest_path = os.path.abspath(__file__).split(os.sep)
libnest_path = os.sep.join(
    libnest_path[0:libnest_path.index('libnest') + 1] + ['src', 'python']
)
sys.path = [libnest_path] + sys.path

from nest import Nest
from nest.tree.exception import MapError
from nest.path.exception import (PathError, MissingParser)
from nest.tree.abstract import AbstractTree
from nest.path.parser import PathParser
from nest.path.iterator import PathIterator
from nest.path.parser.stroke import StrokeParser
from nest.tree.data import DataTree


class NonParsableTree(AbstractTree):
    '''There is no parser registered for it.'''
    pass


class VoidTree(AbstractTree):
    '''It has no data in it.'''
    pass


class VoidParser(PathParser):
    pass


class TestNestTree(unittest.TestCase):

    def setUp(self):
        self.void_nest = Nest(VoidTree, PathParser)
        self.data_nest = Nest(DataTree, StrokeParser)

    def test_nonparsabletree(self):
        self.assertRaises(TypeError, Nest, [None, None])
        nonparsable_nest = Nest(NonParsableTree, PathParser)
        nonparsable_nest.path_parser_type = None  # Overwrite default.
        tree = nonparsable_nest.sample()
        # Should raise an exception.
        self.assertRaises(MissingParser, tree.get, 'not/exists')

    def test_voidtree(self):
        tree = self.void_nest.sample()
        # Should raise an exception.
        self.assertRaises(PathError, tree.get, 'not/exists')

    def test_basic_datatree(self):
        expected_value = 'a value'
        self.assertEquals(
            expected_value,
            Nest(DataTree, StrokeParser).sample()
                .set('some/nested/path', expected_value)
                .get('some/nested/path').value)

    def test_datatree(self):
        data = {
            'existing': { 'path' : 'value'},
        }
        tree = self.data_nest.sample().cover(data)
        self.assertEquals('value', tree.get('existing/path').value)
        self.assertTrue(tree.has_path('existing/path'))
        # Test setting new values.
        tree.set('existing/sibling_path', 'another value')
        self.assertEquals(
            'another value', tree.get('existing/sibling_path').value)
        # More tests with setting.
        tree.set('1/2/3', 'third')
        self.assertEquals(
            'third', tree.get('1/2/3').value)

    def test_map(self):
        data = {
            'existing': { 'path' : 'value'},
        }
        tree = self.data_nest.sample().cover(data)
        cloned = tree.map()
        self.assertNotEquals(tree, cloned)
        self.assertNotEquals(
            tree.get('existing'),
            cloned.get('existing'))
        self.assertNotEquals(
            tree.get('existing/path'),
            cloned.get('existing/path'))
        self.assertEquals(
            tree.get('existing/path').value,
            cloned.get('existing/path').value)



if __name__ == '__main__':
    unittest.main()
    #unittest.main(defaultTest='TestNestTree.test_map')
